#ifndef __WIZ_BASE_UTILS_ENDIAN_HPP__SHANHAOBO_19800429__
#define __WIZ_BASE_UTILS_ENDIAN_HPP__SHANHAOBO_19800429__

#include "../Core/WizBaseCoreTypeInt.hpp"
#include "../WizBaseException.hpp"
#include "../MPL/WizBaseMPLBytesReverse.hpp"

#include <malloc.h>

namespace Wiz
{
    namespace Endian
    {
        enum Type
        {
            eBig,
            eLittle,
        };
        WIZ_DECLARE(::Wiz::Endian::Type);

        struct Native
        {
            static ::Wiz::Endian::Type Test()
            {
                const static ::Wiz::UInt16::Type s_EndianTest = 0x0201;
                const static ::Wiz::UInt8::Ptr s_EndianTestPtr = (::Wiz::UInt8::Ptr)(&s_EndianTest);
                const static ::Wiz::Endian::Type s_Endian = s_EndianTestPtr[0] == 0x01 ? eLittle : eBig; 

                return s_Endian;
            }
        };/// end of struct Native

        struct Storage
        {
            typedef ::Wiz::UInt8::Type      Type;
            const static Type LittleEndian  = 0x01;
            const static Type BigEndian     = 0x02;
        };

        namespace Exception
        {
            class IllegalEndian : public ::Wiz::Exception::Type
            {
                typedef ::Wiz::Exception::Type  tSuper;
            public:
                IllegalEndian() : tSuper("Illegal Endian")
                {}
            public:
            };
        }  /// end of namespace Exception

#if WIZ_CFG_ENDIAN_NATIVE == WIZ_CFG_ENDIAN_LITTLE

        template<class T>
        ::Wiz::Void::Type FromLittleEndianToNative(T& OutData, const T& InData)
        {
            OutData = InData;
        }

        template<class T>
        T FromLittleEndianToNative(const T& InData)
        {
            return InData;
        }

        template<class T>
        ::Wiz::Void::Type FromNativeToLittleEndian(T& OutData, const T& InData)
        {
            OutData = InData;
        }

        template<class T>
        T FromNativeToLittleEndian(const T& InData)
        {
            return InData;
        }

        ///

        template<class T>
        ::Wiz::Void::Type FromBigEndianToNative(T& NativeData, const T& BigEndianData)
        {
            ::Wiz::MPL::ByteReverse<sizeof(T)>
                (
                ::Wiz::Cast::Static<::Wiz::Byte::InPtr>(&BigEndianData),
                ::Wiz::Cast::Static<::Wiz::Byte::OutPtr>(&NativeData)
                );
        }

        template<class T>
        T FromBigEndianToNative(const T& BigEndianData)
        {
            T NativeData;
            ::Wiz::Endian::FromBigEndianToNative(NativeData, BigEndianData);
            return NativeData;
        }

        template<class T>
        ::Wiz::Void::Type  FromNativeToBigEndian(T& BigEndianData, const T& NativeData)
        {
            ::Wiz::MPL::ByteReverse<sizeof(T)>
                (
                ::Wiz::Cast::Static<::Wiz::Byte::InPtr>(&NativeData),
                ::Wiz::Cast::Static<::Wiz::Byte::OutPtr>(&BigEndianData)
                );
        }

        template<class T>
        T FromNativeToBigEndian(const T& NativeData)
        {
            T BigEndianData;
            ::Wiz::Endian::FromNativeToBigEndian(BigEndianData, NativeData);
            return BigEndianData;
        }

#else if (WIZ_CFG_ENDIAN_NATIVE == WIZ_CFG_ENDIAN_BIG)

        //////////////////////////////////////////////////////////////////////////

        template<class T>
        ::Wiz::Void::Type FromLittleEndianToNative(T& NativeData, const T& LittleEndianData)
        {
            ::Wiz::MPL::ByteReverse<sizeof(T)>
                (
                ::Wiz::Cast::Static<::Wiz::Byte::InPtr>(&LittleEndianData),
                ::Wiz::Cast::Static<::Wiz::Byte::OutPtr>(&NativeData)
                );
        }

        template<class T>
        T FromLittleEndianToNative(const T& LittleEndianData)
        {
            T NativeData;
            ::Wiz::Endian::FromLittleEndianToNative(NativeData, LittleEndianData);
            return NativeData;
        }

        template<class T>
        ::Wiz::Void::Type  FromNativeToLittleEndian(T& LittleEndianData, const T& NativeData)
        {
            ::Wiz::MPL::ByteReverse<sizeof(T)>
                (
                ::Wiz::Cast::Static<::Wiz::Byte::InPtr>(&NativeData),
                ::Wiz::Cast::Static<::Wiz::Byte::OutPtr>(&LittleEndianData)
                );
        }

        template<class T>
        T FromNativeToLittleEndian(const T& NativeData)
        {
            T LittleEndianData;
            ::Wiz::Endian::FromNativeToLittleEndian(LittleEndianData, NativeData);
            return LittleEndianData;
        }

        ///

        template<class T>
        ::Wiz::Void::Type FromBigEndianToNative(T& OutData, const T& InData)
        {
            OutData = InData;
        }

        template<class T>
        T FromBigEndianToNative(const T& InData)
        {
            return InData;
        }

        template<class T>
        ::Wiz::Void::Type FromNativeToBigEndian(T& OutData, const T& InData)
        {
            OutData = InData;
        }

        template<class T>
        T FromNativeToBigEndian(const T& InData)
        {
            return InData;
        }
        //////////////////////////////////////////////////////////////////////////
#endif /*WIZ_CFG_ENDIAN_NATIVE*/
    } /// end of namespace Endian
} /// end of namespace Wiz

#endif /*__WIZ_BASE_UTILS_ENDIAN_HPP__SHANHAOBO_19800429__*/
